package com.pactera.redis.utils;

import com.google.common.base.Joiner;
import com.pactera.redis.service.Locker;
import org.apache.commons.lang3.StringUtils;

import java.util.concurrent.TimeUnit;

/**
 * @program: seedland_uc_git
 * @description:
 * @author: EC_liqingdian
 * @create: 2020-04-18 16:49
 **/
public final class LockUtils {

    private LockUtils() {
    }

    private static Locker locker;

    private static String prefix;

    /**
     * 设置工具类使用的locker
     *
     * @param locker redission
     * @param prefix 前缀
     */
    public static LockUtils builder(Locker locker, String prefix) {
        LockUtils.locker = locker;
        LockUtils.prefix = StringUtils.isBlank(prefix) ? "" : prefix;
        return new LockUtils();
    }

    public static Locker locker() {
        return locker;
    }

    /**
     * 拼接前缀
     *
     * @param lockKey 锁
     * @Author: EC_liqingdian
     */
    private static String keyPrefix(String lockKey) {
        return Joiner.on("-").join(LockUtils.prefix, "LOCK::", lockKey);
    }

    /**
     * 获取锁
     *
     * @param lockKey 锁
     */
    public static void lock(String lockKey) {
        locker.lock(keyPrefix(lockKey));
    }

    /**
     * 释放锁
     *
     * @param lockKey 锁
     */
    public static void unlock(String lockKey) {
        locker.unlock(keyPrefix(lockKey));
    }

    /**
     * 获取锁，超时释放
     *
     * @param lockKey 锁
     * @param timeout 超时时间
     */
    public static void lock(String lockKey, int timeout) {
        locker.lock(keyPrefix(lockKey), timeout);
    }

    /**
     * 获取锁，超时释放，指定时间单位
     *
     * @param lockKey 锁
     * @param unit    时间单位
     * @param timeout 超时时间
     */
    public static void lock(String lockKey, TimeUnit unit, int timeout) {
        locker.lock(keyPrefix(lockKey), unit, timeout);
    }

    /**
     * 尝试获取锁，获取到立即返回true,获取失败立即返回false
     *
     * @param lockKey
     * @return
     */
    public static boolean tryLock(String lockKey) {
        return locker.tryLock(keyPrefix(lockKey));
    }

    /**
     * 尝试获取锁，在给定的waitTime时间内尝试，获取到返回true,获取失败返回false,获取到后再给定的leaseTime时间超时释放
     *
     * @param lockKey
     * @param waitTime
     * @param leaseTime
     * @param unit
     * @return
     * @throws InterruptedException
     */
    public static boolean tryLock(String lockKey, long waitTime, long leaseTime,
                                  TimeUnit unit) throws InterruptedException {
        return locker.tryLock(keyPrefix(lockKey), waitTime, leaseTime, unit);
    }

    /**
     * 锁释放被任意一个线程持有
     *
     * @param lockKey
     * @return
     */
    public static boolean isLocked(String lockKey) {
        return locker.isLocked(keyPrefix(lockKey));
    }
}
